package one;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class WordAnalysis {

    public static String[] keys = {
            "const", "int", "char", "void", "main",
            "if", "else", "do", "while", "for", "scanf", "printf", "return",
            "+", "-", "*", "/", "<", "<=", ">", ">=", "==", "!=", "=", ";", ",", "(", ")", "[", "]", "{", "}"
    };
    public static String[] values = {
            "CONSTTK", "INTTK", "CHARTK", "VOIDTK", "MAINTK",
            "IFTK", "ELSETK", "DOTK", "WHILETK", "FORTK", "SCANFTK", "PRINTFTK", "RETURNTK",
            "PLUS", "MINU", "MULT", "DIV", "LSS", "LEQ", "GRE", "GEQ", "EQL", "NEQ", "ASSIGN", "SEMICN", "COMMA", "LPARENT", "RPARENT", "LBRACK", "RBRACK", "LBRACE", "RBRACE"
    };
    public static String[] custom = {
            "IDENFR", "INTCON", "CHARCON", "STRCON"
    };
    public static String[] code = {
            "001", "002", "003", "004", "005"
    };

    /**
     * 读取文件内容为字符串
     * @param file 文件对象
     * @return 返回文件内容字符串
     * @throws IOException
     */
    public static String getFile(File file) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new FileReader(file));
        String data = br.readLine();
        while(data != null){
            sb.append(data + "\n");
            data = br.readLine();
        }
        br.close();
        String files = "";
        for (int i = 0; i < sb.length(); i++) {
            char ch = sb.charAt(i);
            if(ch == '\n'){
                continue;
            }
            if(ch == ' ' && i > 0 && (sb.charAt(i - 1) == ' ' || sb.charAt(i - 1) == '\n')){
                continue;
            }
            files += ch;
        }
        files = files.trim();
        System.out.println("源文件内容为：" + '\n' + files);
        return files;
    }

    /**
     * 判断字符是否为字母
     * @param ch 输入字符
     * @return 输出boolean类型
     */
    public static boolean isLetter(char ch){
        return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
    }

    /**
     * 判断字符是否为数字
     * @param ch 输入字符
     * @return 输出boolean类型
     */
    public static boolean isDigit(char ch){
        return ch >= '0' && ch <= '9';
    }

    /**
     * 从左到右根据词法进行检测，分类标识
     * @param chs 输入字符数组
     * @return 返回分词数组和标识数组
     */
    public static List<List<String>> classify(char[] chs){
        List<List<String>> lists = new ArrayList<>();
        List<String> listKey = new ArrayList<>();
        List<String> listValue = new ArrayList<>();
        int i = 0;
        String word = "";
        char head = 0;
        do {
            char ch = chs[i];
            if (word.length() == 0) {
                head = ch;
            }
            i++;
            if (isLetter(ch)) {
                word += ch;
            } else if (isDigit(ch)) {
                word += ch;
            } else {
                if (isLetter(head)) {
                    listKey.add(word);
                    listValue.add("001");
                } else if (isDigit(head)) {
                    listKey.add(word);
                    listValue.add("002");
                }
                word = "";
                head = 0;
                if (ch != ' ') {
                    if(ch != '\'' && ch != '\"'){
                        if((ch == '!' || ch == '=' || ch == '>' || ch == '<') && chs[i] == '='){
                            word = word + ch + chs[i++];
                        }else{
                            word += ch;
                        }
                        listKey.add(word);
                        listValue.add("003");
                    }else if(ch == '\''){
                        listKey.add(String.valueOf(chs[i++]));
                        listValue.add("004");
                        i++;
                    }else{
                        while(chs[i] != '\"'){
                            word += chs[i++];
                        }
                        listKey.add(word);
                        listValue.add("005");
                        i++;
                    }
                    word = "";
                }
            }
        } while (i != chs.length);
        lists.add(listKey);
        lists.add(listValue);
        return lists;
    }

    public static void writeFile(List<String> listKey, List<String> listValue) throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter("output.txt"));
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < keys.length; i++) {
            map.put(keys[i], values[i]);
        }
        for (int i = 0; i < listKey.size(); i++) {
            String key = listKey.get(i);
            String value = listValue.get(i);
            String outFile = "";
            if(value.equals(code[0]) || value.equals(code[2])){
                boolean isExist = map.containsKey(key);
                if(isExist){
                    outFile = map.get(key);
                }else{
                    outFile = custom[0];
                }
            }else if(value.equals(code[1])){
                outFile = custom[1];
            }else if(value.equals(code[3])){
                outFile = custom[2];
            }else if(value.equals(code[4])){
                outFile = custom[3];
            }
            outFile += " " + key + "\n";
            System.out.print(outFile);
            out.write(outFile);
        }
        out.close();
    }

    public static void main(String[] args) throws IOException {
        File file = new File("testfile.txt");
        String str = getFile(file);
        char[] chs = str.toCharArray();
        List<List<String>> lists = classify(chs);
        List<String> listKey = lists.get(0);
        List<String> listValue = lists.get(1);
        System.out.println("单词对应的类别为：");
        for (int i = 0; i < listKey.size(); i++) {
            System.out.println(listKey.get(i)+"---"+listValue.get(i));
        }
        System.out.println("单词对应的Token字为：");
        writeFile(listKey, listValue);
    }
}
